import { getJSONP } from './getJSONP'
import { loadMaps } from '../view/components/map/maps'

const PI: number = 3.1415926535897932384626
const a: number = 6378245.0
const ee: number = 0.00669342162296594323

export function gcj02towgs84(lng: number, lat: number) {
  lat = +lat
  lng = +lng
  if (outOfChina(lng, lat)) {
    return [lng, lat]
  }
  let dlat = _transformlat(lng - 105.0, lat - 35.0)
  let dlng = _transformlng(lng - 105.0, lat - 35.0)
  const radlat = (lat / 180.0) * PI
  let magic = Math.sin(radlat)
  magic = 1 - ee * magic * magic
  const sqrtmagic = Math.sqrt(magic)
  dlat = (dlat * 180.0) / (((a * (1 - ee)) / (magic * sqrtmagic)) * PI)
  dlng = (dlng * 180.0) / ((a / sqrtmagic) * Math.cos(radlat) * PI)
  const mglat = lat + dlat
  const mglng = lng + dlng
  return [lng * 2 - mglng, lat * 2 - mglat]
}

export function wgs84togcj02(lng: number, lat: number) {
  lat = +lat
  lng = +lng
  if (outOfChina(lng, lat)) {
    return [lng, lat]
  }
  let dlat = _transformlat(lng - 105.0, lat - 35.0)
  let dlng = _transformlng(lng - 105.0, lat - 35.0)
  const radlat = (lat / 180.0) * PI
  let magic = Math.sin(radlat)
  magic = 1 - ee * magic * magic
  const sqrtmagic = Math.sqrt(magic)
  dlat = (dlat * 180.0) / (((a * (1 - ee)) / (magic * sqrtmagic)) * PI)
  dlng = (dlng * 180.0) / ((a / sqrtmagic) * Math.cos(radlat) * PI)
  const mglat = lat + dlat
  const mglng = lng + dlng
  return [mglng, mglat]
}

const outOfChina = function (lng: number, lat: number) {
  return (
    lng < 72.004 || lng > 137.8347 || lat < 0.8293 || lat > 55.8271 || false
  )
}
const _transformlat = function (lng: number, lat: number) {
  let ret =
    -100.0 +
    2.0 * lng +
    3.0 * lat +
    0.2 * lat * lat +
    0.1 * lng * lat +
    0.2 * Math.sqrt(Math.abs(lng))
  ret +=
    ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) *
      2.0) /
    3.0
  ret +=
    ((20.0 * Math.sin(lat * PI) + 40.0 * Math.sin((lat / 3.0) * PI)) * 2.0) /
    3.0
  ret +=
    ((160.0 * Math.sin((lat / 12.0) * PI) + 320 * Math.sin((lat * PI) / 30.0)) *
      2.0) /
    3.0
  return ret
}
const _transformlng = function (lng: number, lat: number) {
  let ret =
    300.0 +
    lng +
    2.0 * lat +
    0.1 * lng * lng +
    0.1 * lng * lat +
    0.1 * Math.sqrt(Math.abs(lng))
  ret +=
    ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) *
      2.0) /
    3.0
  ret +=
    ((20.0 * Math.sin(lng * PI) + 40.0 * Math.sin((lng / 3.0) * PI)) * 2.0) /
    3.0
  ret +=
    ((150.0 * Math.sin((lng / 12.0) * PI) +
      300.0 * Math.sin((lng / 30.0) * PI)) *
      2.0) /
    3.0
  return ret
}

export interface Point {
  latitude: number
  longitude: number
}

export const ICON_PATH_LOCTAION =
  'M13.3334375 16 q0.033125 1.1334375 0.783125 1.8834375 q0.75 0.75 1.8834375 0.75 q1.1334375 0 1.8834375 -0.75 q0.75 -0.75 0.75 -1.8834375 q0 -1.1334375 -0.75 -1.8834375 q-0.75 -0.75 -1.8834375 -0.75 q-1.1334375 0 -1.8834375 0.75 q-0.75 0.75 -0.783125 1.8834375 ZM30.9334375 14.9334375 l-1.1334375 0 q-0.5 -5.2 -4.0165625 -8.716875 q-3.516875 -3.5165625 -8.716875 -4.0165625 l0 -1.1334375 q0 -0.4665625 -0.3 -0.7665625 q-0.3 -0.3 -0.7665625 -0.3 q-0.4665625 0 -0.7665625 0.3 q-0.3 0.3 -0.3 0.7665625 l0 1.1334375 q-5.2 0.5 -8.716875 4.0165625 q-3.5165625 3.516875 -4.0165625 8.716875 l-1.1334375 0 q-0.4665625 0 -0.7665625 0.3 q-0.3 0.3 -0.3 0.7665625 q0 0.4665625 0.3 0.7665625 q0.3 0.3 0.7665625 0.3 l1.1334375 0 q0.5 5.2 4.0165625 8.716875 q3.516875 3.5165625 8.716875 4.0165625 l0 1.1334375 q0 0.4665625 0.3 0.7665625 q0.3 0.3 0.7665625 0.3 q0.4665625 0 0.7665625 -0.3 q0.3 -0.3 0.3 -0.7665625 l0 -1.1334375 q5.2 -0.5 8.716875 -4.0165625 q3.5165625 -3.516875 4.0165625 -8.716875 l1.1334375 0 q0.4665625 0 0.7665625 -0.3 q0.3 -0.3 0.3 -0.7665625 q0 -0.4665625 -0.3 -0.7665625 q-0.3 -0.3 -0.7665625 -0.3 ZM17.0665625 27.6665625 l0 -2.0665625 q0 -0.4665625 -0.3 -0.7665625 q-0.3 -0.3 -0.7665625 -0.3 q-0.4665625 0 -0.7665625 0.3 q-0.3 0.3 -0.3 0.7665625 l0 2.0665625 q-4.3 -0.4665625 -7.216875 -3.383125 q-2.916875 -2.916875 -3.3834375 -7.216875 l2.0665625 0 q0.4665625 0 0.7665625 -0.3 q0.3 -0.3 0.3 -0.7665625 q0 -0.4665625 -0.3 -0.7665625 q-0.3 -0.3 -0.7665625 -0.3 l-2.0665625 0 q0.4665625 -4.3 3.3834375 -7.216875 q2.9165625 -2.916875 7.216875 -3.3834375 l0 2.0665625 q0 0.4665625 0.3 0.7665625 q0.3 0.3 0.7665625 0.3 q0.4665625 0 0.7665625 -0.3 q0.3 -0.3 0.3 -0.7665625 l0 -2.0665625 q4.3 0.4665625 7.216875 3.3834375 q2.9165625 2.9165625 3.383125 7.216875 l-2.0665625 0 q-0.4665625 0 -0.7665625 0.3 q-0.3 0.3 -0.3 0.7665625 q0 0.4665625 0.3 0.7665625 q0.3 0.3 0.7665625 0.3 l2.0665625 0 q-0.4665625 4.3 -3.383125 7.216875 q-2.916875 2.9165625 -7.216875 3.383125 Z'

export const ICON_PATH_ORIGIN =
  ''
export const ICON_PATH_TARGET =
  ''

export const enum MapType {
  QQ = 'qq',
  GOOGLE = 'google',
  AMAP = 'AMap',
  BMAP = 'BMapGL',
  UNKNOWN = '',
}

export type TranslateCoordinateSystemOptions = ({
  coords,
  skip,
}: {
  coords: GeolocationCoordinates
  skip?: boolean
}) => void

let mapInfo: any = null

function parseMapInfo() {
  if (__uniConfig.qqMapKey) {
    return {
      type: MapType.QQ,
      key: __uniConfig.qqMapKey,
    }
  }
  return {
    type: MapType.UNKNOWN,
    key: '',
  }
}

export async function getMapInfo() {
  if (mapInfo) {
    return mapInfo
  }
  return parseMapInfo()
}

let IS_AMAP = false
let hasGetIsAMap = false
export const getIsAMap = () => {
  if (hasGetIsAMap) {
    return IS_AMAP
  } else {
    hasGetIsAMap = true
    return (IS_AMAP = mapInfo?.type === MapType.AMAP)
  }
}

export const getIsBMap = () => {
  return mapInfo?.type === MapType.BMAP
}

export function translateCoordinateSystem(
  type: string | undefined,
  coords: GeolocationCoordinates,
  skip?: boolean
) {
  const wgs84Map = [MapType.GOOGLE]
  if (
    (type && type.toUpperCase() === 'WGS84') ||
    wgs84Map.includes(mapInfo?.type) ||
    skip
  ) {
    return Promise.resolve(coords)
  }
  if (mapInfo.type === MapType.QQ) {
    return new Promise((resolve: GeolocationCoordinates | any) => {
      getJSONP(
        `https://apis.map.qq.com/jsapi?qt=translate&type=1&points=${coords.longitude},${coords.latitude}&key=${mapInfo.key}&output=jsonp&pf=jsapi&ref=jsapi`,
        {
          callback: 'cb',
        },
        (res: any) => {
          if (
            'detail' in res &&
            'points' in res.detail &&
            res.detail.points.length
          ) {
            const { lng, lat } = res.detail.points[0]
            resolve({
              longitude: lng,
              latitude: lat,
              altitude: coords.altitude,
              accuracy: coords.accuracy,
              altitudeAccuracy: coords.altitudeAccuracy,
              heading: coords.heading,
              speed: coords.speed,
            })
          } else {
            resolve(coords)
          }
        },
        () => resolve(coords)
      )
    })
  }
  if (mapInfo.type === MapType.AMAP) {
    return new Promise((resolve: GeolocationCoordinates | any) => {
      loadMaps([], () => {
        window.AMap.convertFrom(
          [coords.longitude, coords.latitude],
          'gps',
          (_: string, res: any) => {
            if (res.info === 'ok' && res.locations.length) {
              const { lat, lng } = res.locations[0]
              resolve({
                longitude: lng,
                latitude: lat,
                altitude: coords.altitude,
                accuracy: coords.accuracy,
                altitudeAccuracy: coords.altitudeAccuracy,
                heading: coords.heading,
                speed: coords.speed,
              })
            } else {
              resolve(coords)
            }
          }
        )
      })
    })
  }
  return Promise.reject(
    new Error(
      'translate coordinate system faild, map provider not configured or not supported'
    )
  )
}
